/*
    This file is part of Picasa Album Downloader.

    Picasa Album Downloader is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Picasa Album Downloader is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Picasa Album Downloader.  If not, see <http://www.gnu.org/licenses/>.
*/
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.Thread.State;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import javax.swing.BoxLayout;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import com.google.gdata.client.photos.PicasawebService;
import com.google.gdata.data.photos.AlbumEntry;
import com.google.gdata.data.photos.AlbumFeed;
import com.google.gdata.data.photos.UserFeed;
import com.google.gdata.util.ServiceException;

public class PicasaDlApplet extends JApplet implements ActionListener {
	
	class ThreadProgress {
		ThreadProgress(String album, WorkerThread thr, JProgressBar bar) {
			albumName = album;
			thread = thr;
			progressBar = bar;
		}
		WorkerThread thread;
		JProgressBar progressBar;
		String albumName;
	}
	
	
	PicasawebService picasaService = new PicasawebService("picasadl-applet");

	JLabel labelOwner;
	JPanel panelOwner;
	JTextField textOwner;
	JButton buttonLoadAlbums;

	JPanel panelAlbums;
	JTable tableAlbums;
	AlbumTableModel tableModel;
	
	JButton buttonDownloadAlbum;
	
	JPanel panelStatus;
	JTextField labelStatus;
	JPanel progressBars;
	BlockingQueue<WorkerThread> downloadQueue;

	ConsumerThread consumerThread;
	
	LinkedList<ThreadProgress> progressData;

	public void init() {
		// Execute a job on the event-dispatching thread:
		// creating this applet's GUI.
		try {
			downloadQueue = new LinkedBlockingQueue<WorkerThread>();
			consumerThread = new ConsumerThread(downloadQueue);
			consumerThread.start();
			progressData = new LinkedList<ThreadProgress>();
			SwingUtilities.invokeAndWait(new Runnable() {
				public void run() {
					createGUI();
				}
			});
		} catch (Exception e) {
			System.err.println("createGUI didn't successfully complete: " + e);
			e.printStackTrace();
		}
	}

	private void createGUI() {
		// Create the text field and make it uneditable.
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
		}
		panelOwner = new JPanel();
		panelOwner.setLayout(new BoxLayout(panelOwner, BoxLayout.X_AXIS));

		labelOwner = new JLabel("Album owner id: ", JLabel.CENTER);
		panelOwner.add(labelOwner);

		textOwner = new JTextField("sochotnicky", 100);
		textOwner.addActionListener(this);
		panelOwner.add(textOwner);

		buttonLoadAlbums = new JButton("Load album names");
		buttonLoadAlbums.addActionListener(this);
		panelOwner.add(buttonLoadAlbums);

		buttonDownloadAlbum = new JButton("Download album");
		buttonDownloadAlbum.addActionListener(this);
		panelOwner.add(buttonDownloadAlbum);
		
		// Set the layout manager so that the text field will be
		// as wide as possible.
		setLayout(new BorderLayout());
		add(panelOwner, BorderLayout.NORTH);

		panelAlbums = new JPanel(new BorderLayout());
		
		tableModel = new AlbumTableModel();
		tableAlbums = new JTable(tableModel);
		tableAlbums.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
		tableAlbums.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		
		JScrollPane jsp = new JScrollPane(tableAlbums);

		panelAlbums.add(jsp, BorderLayout.CENTER);


		add(panelAlbums, BorderLayout.CENTER);

		labelStatus = new JTextField("Applet ready");
		labelStatus.setEditable(false);
		
		panelStatus = new JPanel();
		panelStatus.setLayout(new BoxLayout(panelStatus, BoxLayout.Y_AXIS));
		
		progressBars = new JPanel();
		progressBars.setLayout(new BoxLayout(progressBars, BoxLayout.Y_AXIS));
		progressBars.setPreferredSize(new Dimension(progressBars.getPreferredSize().width,50));
		
		panelStatus.add(progressBars);
		panelStatus.add(labelStatus);
		
		add(panelStatus, BorderLayout.SOUTH);
		setVisible(true);
	}

	public void destroy() {
		cleanUp();
	}

	private void cleanUp() {
		// Execute a job on the event-dispatching thread:
		// taking the text field out of this applet.
		try {
			SwingUtilities.invokeAndWait(new Runnable() {
				@SuppressWarnings("deprecation")
				public void run() {
					
					remove(panelAlbums);
					remove(panelOwner);
					tableAlbums = null;
					labelStatus = null;
					labelOwner = null;
					buttonLoadAlbums = null;
					buttonDownloadAlbum = null;
					consumerThread.stop();
				}
			});
		} catch (Exception e) {
			System.err.println("cleanUp didn't successfully complete");
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		Object source = e.getSource();
		System.out.println("action");
		try {
			if (source == buttonLoadAlbums || source == textOwner) {
				if (textOwner.getText().isEmpty()) {
					JOptionPane.showMessageDialog(this,
							"You must provide user id", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				loadAlbums();
			} else {
				if (tableAlbums.getSelectedRowCount() == 0) {
					JOptionPane.showMessageDialog(this,
							"Select albums to be downloaded", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				File dir = selectOutputDirectory();
				int [] rows = tableAlbums.getSelectedRows();
				for (int i : rows) {
					AlbumEntry album = ((AlbumTableModel)tableAlbums.getModel()).entries.get(i);
					downloadAlbum(album, dir);
				}

			}

		} catch (Exception ex) {
			System.err.println(ex);
			JOptionPane.showMessageDialog(this, ex.toString(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	public void downloadAlbum(AlbumEntry album, File dir) throws MalformedURLException, IOException,
			ServiceException, FileNotFoundException {
		if (dir == null)
			return;

		URL feedUrl = new URL("http://picasaweb.google.com/data/feed/api/user/"
				+ textOwner.getText() + "/album/" + album.getName());
		System.out.println(feedUrl);
		dir = new File(dir.getAbsolutePath()+File.separator+album.getName());
		if(dir.exists()) {
			if(JOptionPane.showConfirmDialog(this, "Output directory exists. Files will be truncated. Are you sure?",
							"Warning",JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
				return;
			}
		} else {
			dir.mkdir();
		}
		AlbumFeed feed = picasaService.getFeed(feedUrl, AlbumFeed.class);

		WorkerThread thr = new WorkerThread(this,
				WorkerThread.WorkerType.ALBUM_DOWNLOADER, feed
						.getPhotoEntries(), dir);
		JProgressBar progressBar = new JProgressBar(0, 100);
		progressBar.setStringPainted(true);
		progressBar.setString(album.getName() + " 0 %");
		progressBar.setValue(0);
		progressBars.add(progressBar);
		progressBars.revalidate();
		
		progressData.add(new ThreadProgress(album.getName(),thr, progressBar));
		
		downloadQueue.add(thr);
	}

	public void loadAlbums() throws MalformedURLException, IOException,
			ServiceException {
		System.out.println("loading");
		URL feedUrl = new URL("http://picasaweb.google.com/data/feed/api/user/"
				+ textOwner.getText() + "?kind=album");

		UserFeed myUserFeed = picasaService.getFeed(feedUrl, UserFeed.class);
		tableModel.clear();

		List<AlbumEntry> albums = myUserFeed.getAlbumEntries();

		new Thread(new WorkerThread(this, WorkerThread.WorkerType.ALBUM_LOADER,
				albums, null)).start();
	}

	private File selectOutputDirectory() {
		JFileChooser ch = new JFileChooser();
		ch.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		ch.setDialogType(JFileChooser.SAVE_DIALOG);
		if (ch.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
			return ch.getSelectedFile();
		} else {
			return null;
		}
	}

	public void setStatus(String message) {
		labelStatus.setText(message);
	}

	public void addAlbum(AlbumEntry album) {
		tableModel.addAlbum(album);
	}
	
	public void updateProgress(WorkerThread thread) {
		for(ThreadProgress cur: progressData) {
			if(cur.thread == thread) {
				double progress = thread.getProgress();
				if(progress == 1.0 || thread.getState().equals(State.TERMINATED)) {
					for(Component c: progressBars.getComponents()) {
						if(c == cur.progressBar) {
							progressBars.remove(cur.progressBar);
							progressData.remove(cur);
							cur.progressBar = null;
							progressBars.revalidate();
							return;
						}
					}
				}
				cur.progressBar.setValue((int)(progress*100));
				cur.progressBar.setString(cur.albumName + " " + (int)(progress*100) + " %");
				cur.progressBar.repaint();
			}
		}
	}
}
